﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Top.Core;
using Top.Core.Api;

namespace Top.Redis.Session
{
    /// <summary>
    /// 分布式session redis实现
    /// </summary>
    public class SessionByRedis :IApiSession
    {
        private Dictionary<string, object> _items;

        /// <summary>
        /// 分布式Session前缀
        /// </summary>
        public static string SessionPrefix
        {
            get;
            set;
        }

        /// <summary>
        /// 设置session redis配置
        /// </summary>
        static SessionByRedis()
        {
            SessionPrefix = Top.Core.Configs.AppSettings["SessionPrefix"];

            if (!string.IsNullOrEmpty(SessionPrefix))
            {
                SessionPrefix = SessionPrefix + ".";
            }

            RedisProvider.SetConfig("SessionMaster", "SessionSlave");
        }

        public event EventHandler OnAbandoned;

        public void Abandon()
        {
            try
            {
                RedisProvider.SessionKeyDelSync("Session." + SessionPrefix + SessionID);
            }
            catch (Exception ex)
            {
                Trace.Write(ex);
            }

            _items.Clear();
            var temp = OnAbandoned;

            if (temp != null)
            {
                temp(this, EventArgs.Empty);
            }

            SessionID = SessionIDFactiory.Create();
            IsNewSession = true;
        }

        public void Add(string key, object value)
        {
            this[key] = value;
        }

        public void Clear()
        {
            _items.Clear();
        }

        public bool ContainsKey(string key)
        {
            return _items.ContainsKey(key);
        }

        public KeyValuePair<string, object>[] ToArray()
        {
            var array = new KeyValuePair<string, object>[_items.Count];
            ((ICollection<KeyValuePair<string, object>>)_items).CopyTo(array, 0);
            return array;
        }

        public int Count
        {
            get { return _items.Count; }
        }

        public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
        {
            return _items.GetEnumerator();
        }

        public bool IsNewSession { get; private set; }

        public ICollection<string> Keys
        {
            get { return _items.Keys; }
        }

        public bool Remove(string key)
        {
            return _items.Remove(key);
        }

        public string SessionID { get; private set; }

        public object this[string key]
        {
            get
            {
                if (key == null || key.Length == 0 || key[0] == '!')
                {
                    return null;
                }
                object value;
                if (_items.TryGetValue(key, out value))
                {
                    return value;
                }

                try
                {
                    string rv = RedisProvider.HashGetSync("Session." + SessionPrefix + SessionID, key);

                    if (string.IsNullOrEmpty(rv))
                    {
                        value = rv;
                    }
                    else
                    {
                        value = Json.ToObject(rv);
                    }

                    RedisProvider.HashSetSync("Session." + SessionPrefix + SessionID, key, rv);
                }
                catch (Exception ex)
                {
                    Trace.Write(ex);
                }

                return _items[key] = value;
            }
            set
            {
                if (key == null || key.Length == 0 || key[0] == '!')
                {
                    throw new ArgumentOutOfRangeException("Key的格式不正确");
                }
                if (value == null)
                {
                    Remove(key);
                }
                else
                {
                    _items[key] = value;
                }
            }
        }

        public int Timeout { get; set; }

        public void Init(string sessionid)
        {
            if (sessionid != null)
            {
                try
                {
                    bool isExists = RedisProvider.SessionKeyExistSync("Session." + SessionPrefix + sessionid);

                    if (isExists)
                    {
                        _items = new Dictionary<string, object>();
                        SessionID = sessionid;
                        return;
                    }
                }
                catch (Exception ex)
                {
                    Trace.Write(ex);
                }
            }

            _items = new Dictionary<string, object>();
            SessionID = SessionIDFactiory.Create();
            IsNewSession = true;
        }

        public void Save()
        {
            var timeout = Timeout;

            if (timeout == 0)
            {
                timeout = 3600 * 2; //两小时过期
            }

            try
            {
                if (_items != null && _items.Count > 0)
                {
                    RedisProvider.HashSetSync("Session." + SessionPrefix + SessionID, _items, new TimeSpan(0, 0, timeout));
                }
            }
            catch (Exception ex)
            {
                Trace.Write(ex);
            }
        }
    }
}
